package top.iflyoung.cim.route.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.iflyoung.cim.common.enums.StatusEnum;
import top.iflyoung.cim.common.facade.BaseChatFacade;
import top.iflyoung.cim.common.pojo.CIMUserInfo;
import top.iflyoung.cim.common.pojo.RouteInfo;
import top.iflyoung.cim.common.req.GroupMessageVo;
import top.iflyoung.cim.common.req.P2PMessageVo;
import top.iflyoung.cim.common.util.RouteInfoParseUtil;
import top.iflyoung.cim.common.util.VerifyUtil;
import top.iflyoung.cim.route.constant.RedisPrefix;
import top.iflyoung.cim.route.translator.MessageTranslator;

import java.util.List;
import java.util.Set;

/**
 * @author liguiyang
 * @description
 * @sine 1.8
 * @date 2021/9/418:39
 **/
@Transactional
@Service("redisChatFacadeService")
public class RedisChatFacadeService implements BaseChatFacade {

    private static final Logger logger = LoggerFactory.getLogger(RedisChatFacadeService.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    @Qualifier("sqlChatFacadeService")
    private BaseChatFacade chatFacadeService;
    @Autowired
    private MessageTranslator messageTranslator;

    @Override
    public CIMUserInfo register(String username) {
        throw new UnsupportedOperationException("Redis不能使用这种注册方式");
    }

    @Override
    public CIMUserInfo register(CIMUserInfo userInfo) {
        //注册到数据库
        userInfo = chatFacadeService.register(userInfo);
        String key = RedisPrefix.ACCOUNT_PREFIX.toString() + userInfo.getUserId();
        //如果不包含这个key
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().set(key, userInfo.getUserName());
        }
        return userInfo;
    }

    @Override
    public StatusEnum login(CIMUserInfo userInfo) {
        String key = RedisPrefix.ACCOUNT_PREFIX.toString() + userInfo.getUserId();
        //redis不存在
        if (!redisTemplate.hasKey(key)) {
            StatusEnum dbResult = chatFacadeService.login(userInfo);
            if (!StatusEnum.SUCCESS.equals(dbResult)) {
                return dbResult;
            }
            //设置redis登录状态
            redisTemplate.opsForValue().set(key, userInfo.getUserName());
        }
        try {
            //检验是否重复登录
            if (!saveAndCheckUserLoginStatus(userInfo.getUserId())) {
                return StatusEnum.REPEAT_LOGIN;
            }
        } catch (Exception e) {
            logger.error("redis保存登录状态出错", e);
        }
        return StatusEnum.SUCCESS;
    }

    @Override
    public boolean saveChatRouteInfo(CIMUserInfo userInfo, RouteInfo routeInfo) {
        String key = RedisPrefix.ROUTE_PREFIX.toString() + userInfo.getUserId();
        if (!redisTemplate.hasKey(key)) {
            chatFacadeService.saveChatRouteInfo(userInfo, routeInfo);
            redisTemplate.opsForValue().set(key, RouteInfoParseUtil.parse(routeInfo));
        }
        return redisTemplate.hasKey(key);
    }

    @Override
    public boolean offline(CIMUserInfo userInfo) {
        chatFacadeService.offline(userInfo);
        //删除路由信息
        redisTemplate.delete(RedisPrefix.ROUTE_PREFIX.toString() + userInfo.getUserId());
        redisTemplate.opsForSet().remove(RedisPrefix.LOGIN_STATUS_PREFIX.toString(), userInfo.getUserId());
        return true;
    }

    @Override
    public Set<String> getMembersByGroupId(Long groupId) {
        String key = RedisPrefix.GROUP_PREFIX.toString() + groupId;
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForSet().add(key, chatFacadeService.getMembersByGroupId(groupId).toArray(new String[]{}));
        }
        return redisTemplate.opsForSet().members(key);
    }

    @Override
    public RouteInfo getUserRouteInfo(Long userId) {
        String key = RedisPrefix.ROUTE_PREFIX.toString() + userId;
        if (redisTemplate.hasKey(key)) {
            return RouteInfoParseUtil.parse(redisTemplate.opsForValue().get(key));
        }
        RouteInfo info = chatFacadeService.getUserRouteInfo(userId);
        if (VerifyUtil.isEmpty(info)) {
            throw new IllegalArgumentException("该用户还没有上线");
        }
        return info;
    }

    @Override
    public CIMUserInfo getUserInfo(Long userId) {
        String key = RedisPrefix.ACCOUNT_PREFIX.toString() + userId;
        if (!redisTemplate.hasKey(key)) {
            CIMUserInfo info = chatFacadeService.getUserInfo(userId);
            redisTemplate.opsForValue().set(key, info.getUserName());
        }
        return new CIMUserInfo(userId, redisTemplate.opsForValue().get(key));
    }

    @Override
    public Set<String> getOnlineUserIds() {
        if (!redisTemplate.hasKey(RedisPrefix.LOGIN_STATUS_PREFIX.toString())) {
            Set<String> userIds = chatFacadeService.getOnlineUserIds();
            redisTemplate.opsForSet().add(RedisPrefix.LOGIN_STATUS_PREFIX.toString(), userIds.toArray(new String[]{}));
        }
        return redisTemplate.opsForSet().members(RedisPrefix.LOGIN_STATUS_PREFIX.toString());
    }

    @Override
    public boolean saveAndCheckUserLoginStatus(Long userId) {
        Long result = redisTemplate.opsForSet().add(RedisPrefix.LOGIN_STATUS_PREFIX.toString(), userId.toString());
        return 0 != result.intValue();
    }

    /**
     * 发送消息的评率太高，不建议mysql直接操作
     *
     * @param messageVo
     * @return
     */
    @Override
    public boolean saveP2PMessage(P2PMessageVo messageVo) {
        return messageTranslator.parseP2PMessageToRedis(messageVo);
    }

    /**
     * 发送消息的评率太高，不建议mysql直接操作
     *
     * @param messageVo
     * @return
     */
    @Override
    public boolean saveGroupMessage(GroupMessageVo messageVo) {
//        throw new UnsupportedOperationException("Redis暂时不保存群聊数据：" + messageVo.toString());
        return messageTranslator.parseGroupMessageToRedis(messageVo);
    }

    @Override
    public boolean saveGroupMessages(List<GroupMessageVo> messages) {
        throw new UnsupportedOperationException("Redis暂时不保存群聊数据：" + messages.toString());
    }

    @Override
    public boolean saveP2PMessages(List<P2PMessageVo> messages) {
        throw new UnsupportedOperationException("Redis暂时不保存私聊数据：" + messages.toString());
    }
}
